/*
 * osobnik_mieszany.h
 *
 * Copyright (C) 2008, 2009
 *
 * Lukasz Bieniasz-Krzywiec
 * Dariusz Leniowski
 *
 * Klasy osobnikow
 */

#ifndef OSOBNIK_MIESZANY_H_
#define OSOBNIK_MIESZANY_H_

#include "osobnik.h"

/* Graf */
class graf {
public:
  // konstruktor
  graf () {}
  // nazwa grafu
  const char * nazwa;
  // zwraca true jezeli istnieje krawedz pomiedzy wierzcholkami u i v
  virtual bool krawedz(int u, int v) { return true; }
  virtual void rozmiar(FILE *f) {}
  virtual void wypisz(FILE *f) {
    int x;
    FOREN(x) {
      fprintf(f, REALF, (populacja[x]->utworzony >= time) ? -1.0 : (real)populacja[x]->strategia);
      if (x < N-1) fprintf(f, " ");
    }
    fprintf(f, "\n");
    FOREN(x) {
      fprintf(f, REALF, populacja[x]->fitness);
      if (x < N-1) fprintf(f, " ");
    }
    fprintf(f, "\n\n");
  }
};

extern graf * grf;

template <class lubi>
class osobnik_mieszany : public osobnik {
public:
  const real s; // strategia
  bool *g; // graf
  osobnik_mieszany(int ktory, int rodzaj, real _s) :
    osobnik(ktory, rodzaj), s(_s) {
    g = new bool[N];
    int v;
    FOREN(v) g[v] = grf->krawedz(n, v);
  }
  ~osobnik_mieszany() {
    delete g;
  }
  void nowa_strategia() {
	  strategia = s;
  }
  void rozpoczecie_epoki() {
    int v;
    FOREN(v) krawedzie[v] = g[v]? lubi::krawedz(n, v) : 0;
  }
  void zakonczenie_epoki() {}
  void wypisz(FILE *F) {
    fprintf(F, "omieszany("REALF", %s)", s, lubi::nazwa);
  }
};

class lubi_losowy {
public:
  static const char * nazwa;
  static real krawedz(int n, int v) { return r->rand(); }
};

class lubi_wszystkich {
public:
  static const char * nazwa;
  static real krawedz(int n, int v) { return 1.0; }
};

/*
 * Założenia:
 *  - strategia osobnika v jest już ustawiona
 */
class lubi_wspolprace {
public:
  static const char * nazwa;
  static real krawedz(int n, int v) {
	real st = (populacja[v]->utworzony >= time-1) ? r->rand(2) : (real)populacja[v]->strategia;
    if (st == -2.0) st = 1.0;
    return st;
  }
};

/*
 * Z C łączy się zawsze, z D łączy się losowo.
 *
 * Założenia:
 *  - strategia osobnika v jest już ustawiona
 */
class lubi_wspolprace2 {
public:
  static const char * nazwa;
  static real krawedz(int n, int v) {
	real st = (populacja[v]->utworzony >= time-1) ? r->rand(2) : (real)populacja[v]->strategia;
    if (st == -2.0) st = 1.0;
    return 1.0 - (1.0-st)*r->rand();
  }
};

/*
 * Założenia:
 *  - fitness osobnika v jest już policzony
 */
class lubi_fitness {
public:
  static const char * nazwa;
  static real krawedz(int n, int v) { return populacja[v]->fitness >= populacja[n]->fitness ? 1.0 : 0.0; }
};


/* Graf pelny */
class graf_pelny : public graf {
public:
  // konstruktor
  graf_pelny();
  // nazwa
  const char * nazwa;
  // zwraca true jezeli istnieje krawedz pomiedzy wierzcholkami u i v
  bool krawedz(int u, int v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", N, 1); }
};

/* Graf 1D, pierscien */
class graf_pierscien : public graf {
public:
  const char * nazwa;
  graf_pierscien();
  bool krawedz(int u, int v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", N, 1); }
};

/* Graf 2D, sasiedztwo 4-ro punktowe (kierunki kardynalne)
 * Zalozenia:
 *  - rozmiar populacji jest podzielny przez SZER
 *  - SZER > 1
 */
template <int SZER>
class graf_krata4 : public graf {
public:
  const char * nazwa;
  graf_krata4();
  bool krawedz(int u, int v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", SZER, N/SZER); }
};

/* Graf 2D, sasiedztwo 6-cio punktowe (plastry miodu, troche skoszone)
 * Zalozenia:
 *  - rozmiar populacji jest podzielny przez SZER
 *  - SZER > 1
 */
template <int SZER>
class graf_krata6 : public graf {
public:
  const char * nazwa;
  graf_krata6();
  bool krawedz(int _u, int _v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", SZER, N/SZER); }
};

/* Graf 2D, sasiedztwo 8-cio punktowe (krol szachowy)
 * Zalozenia:
 *  - rozmiar populacji jest podzielny przez SZER
 *  - SZER > 1
 */
template <int SZER>
class graf_krata8 : public graf {
public:
  const char * nazwa;
  graf_krata8();
  bool krawedz(int _u, int _v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", SZER, N/SZER); }
};

/* Graf 3D, krata, sasiedztwo w kierunkach kardynalnych
 * Zalozenia:
 *  - rozmiar populacji jest podzielny przez SZER*WYS
 *  - SZER > 1, WYS > 1
 */
template <int SZER, int WYS>
class graf_krata_3D : public graf {
public:
  const char * nazwa;
  graf_krata_3D();
  bool krawedz(int u, int v);
  void rozmiar(FILE *f) { fprintf(f, "%d %d\n\n", N, 1); }
};

template <int SZER>
graf_krata4<SZER>::graf_krata4() : nazwa("graf_krata4") {}

template <int SZER>
bool graf_krata4<SZER>::krawedz(int u, int v) {
  int uv;
  if (u >= v) uv = u - v;
  else uv = v - u;
  if (uv == SZER || uv == N - SZER) return true; // sasiedztwo pionowe
  if (u/SZER == v/SZER && (uv == 1 || uv == SZER-1)) return true; // sasiedzstwo poziome
  return false;
}


template <int SZER>
graf_krata6<SZER>::graf_krata6() : nazwa("graf_krata6") {}

template <int SZER>
bool graf_krata6<SZER>::krawedz(int _u, int _v) {
  int u, v, uv;
  if (_u <= _v) {
    u = _u;
    v = _v;
  } else {
    u = _v;
    v = _u;
  }
  uv = v - u; // v >= u
  if (uv == SZER || uv == N - SZER) return true; // sasiedztwo pionowe
  if (uv == 1 || (uv == SZER-1 && u%SZER == 0) || uv == N-1)
	  return true; // sasiedzstwo poziome i skosne
  if ((uv == SZER+1 && u%SZER != SZER-1)
		  || (uv == N - (SZER+1) && u%SZER != 0))
	  return true; // sasiedztwo skosne NW-SE part 2
  return false;
}


template <int SZER>
graf_krata8<SZER>::graf_krata8() : nazwa("graf_krata8") {}

template <int SZER>
bool graf_krata8<SZER>::krawedz(int _u, int _v) {
  int u, v, uv;
  if (_u <= _v) {
    u = _u;
    v = _v;
  } else {
    u = _v;
    v = _u;
  }
  uv = v - u; // u <= v
  if (uv == SZER || uv == N - SZER) return true;
  if (uv == 1 || uv == SZER-1 || uv == N-1) return true;
  if ((uv == SZER+1 && u%SZER != SZER-1) || uv == N - (SZER-1)
		  || (uv == N-(SZER+1) && u%SZER != 0)) return true;
  if ((uv == SZER+SZER-1 && u%SZER == 0)
		  || (uv == N-SZER-SZER+1 && u%SZER == SZER-1)) return true;
  return false;
}


template <int SZER, int WYS>
graf_krata_3D<SZER, WYS>::graf_krata_3D() : nazwa("graf_krata_3D") {}

template <int SZER, int WYS>
bool graf_krata_3D<SZER, WYS>::krawedz(int u, int v) {
  int ux, uy, uz, vx, vy, vz;
  ux = u % SZER; u /= SZER;
  uy = u % WYS;
  uz = u / WYS;
  vx = v % SZER; v /= SZER;
  vy = v % WYS;
  vz = v / WYS;
  if ((ux - vx == 1 || ux - vx == -1 || ux - vx == WYS - 1 || ux - vx == 1 - WYS)
      && uy == vy && uz == vz) return true; // sasiedztwo x
  if ((uy - vy == 1 || uy - vy == -1 || uy - vy == SZER - 1 || uy - vy == 1 - SZER)
      && ux == vx && uz == vz) return true; // sasiedztwo x
  if ((uz - vz == 1 || uz - vz == -1 || uz - vz == (N/SZER/WYS) - 1 || uz - vz == 1 - (N/SZER/WYS))
      && ux == vx && uy == vy) return true; // sasiedztwo x
  return false;
}

#endif /* OSOBNIK_MIESZANY_H_ */
